"""
Author: Jian SuiYue kaohx0214@yeah.net
Date: 2025-05-15 10:35:00
LastEditTime: 2025-05-23 15:10:18
FilePath: LibraryManagerStudio/web/routes/user_api.py
"""
import os.path
from asyncio import sleep
from dataclasses import field
from typing import Optional

import aiofiles
import requests
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Query
from fastapi.responses import JSONResponse

from loguru import logger
from .token_api import validate_jwt, generate_jwt
from .utils import save_cover, WXBizDataCrypt, verify_admin
from ..config import APPID, APPSECRET
from ..deps import get_db
from ...database import DBManager
from ...datamodel import User, Token, UserLoginResp, UserUpdateData
from ...datamodel import WxLoginRequest
from ..config import STATIC_USER_AVATAR_PATH
from pydantic import BaseModel

"""
/login
/get/{user_id}
/gets
/new
/update
/delete/{user_id}
"""
# 创建路由
router = APIRouter()

AVATAR_PATH = os.path.join(
    os.path.dirname(
        os.path.dirname(os.path.abspath(__file__))
    ),
    'static', 'avatar'
)


@router.get("/login")
async def login_user(code: str = Query(...), db: DBManager = Depends(get_db)):
    """
    User login , while wechat_id not in User table
    we will register this wechat_id with relative info become a user

    Args:
        code: str
        db: DBManager
    """

    params = {
        'appid': APPID,
        'secret': APPSECRET,
        'js_code': code,
        'grant_type': 'authorization_code'
    }
    response = requests.get('https://api.weixin.qq.com/sns/jscode2session', params=params).json()

    if 'errcode' in response:
        logger.error(f"{response['errmsg']}")
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                            detail=response['errmsg'])
    openid, session_key = response['openid'], response['session_key']

    if not openid or not session_key:
        logger.error("Unexcepted error at get openid and session Key")
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                            detail="Unexcepted error at get openid and session Key")

    user_exist = db.get(User, filters={"wechat_id": openid})
    uid, is_new_user = None, False
    avatar_url, nick_name = None, None
    if not user_exist.data or not user_exist.status:
        # new User
        user = User(wechat_id=openid, username='微信用户', is_admin=False)
        db.upsert(user)
        res = db.get(User, filters={"wechat_id": openid})
        uid = res.data[0].id
        is_new_user = True
    else:
        user_data = user_exist.data[0]
        avatar_url = user_data.cover
        nick_name = user_data.username
        uid = user_data.id
    token = generate_jwt(user_id=uid, db=db)

    resp = UserLoginResp(uid=uid, token=token, isNewUser=is_new_user,
                         avatarUrl=avatar_url, nickName=nick_name)

    return {"status": True, "data": resp}


@router.post("/avatar")
async def receive_avatar(
        login: str = Query(...),
        uid: int = Query(...),
        avatar: UploadFile = File(...),
        db: DBManager = Depends(get_db)
):
    validate_jwt(login, db)

    # 验证用户存在
    user = db.get(User, filters={"id": uid})
    if not user.data:
        raise HTTPException(status_code=404, detail="用户不存在")

    # 准备保存路径
    file_ext = avatar.filename.split('.')[-1].lower()
    filename = f"{uid}.{file_ext}"
    save_path = os.path.join(AVATAR_PATH, filename)

    # 异步保存文件
    try:
        async with aiofiles.open(save_path, 'wb') as f:
            await f.write(await avatar.read())
    except Exception as e:
        logger.error(f"文件保存失败: {str(e)}")
        raise HTTPException(status_code=500, detail="头像保存失败")

    # 更新用户记录
    try:
        user.data[0].cover = f'/static/avatar/{filename}'
        res = db.upsert(user.data[0])
        logger.critical(f"update avatar: {res}")
    except Exception as e:
        logger.error(f"数据库更新失败: {str(e)}")
        raise HTTPException(status_code=500, detail="用户记录更新失败")

    return {"status": True, "avatarUrl": f"/static/avatar/{filename}"}


@router.get("/get")
async def get_user_profile(
        login: str = Query(...),
        uid: int = Query(..., ge=1),
        db: DBManager = Depends(get_db)
):
    """
    Get user profile by user_id
    
    GET /get?login={your_token}&uid={uid}
    Args:
        token: Token.id
        user_id: User.id
        db: DBManager
    """
    # verify
    validate_jwt(login, db)
    # get
    user = db.get(User, filters={"id": uid})
    if not user.status or not user.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"User ID: {uid} Not found")
    # return
    return {"status": True, "data": user.data[0]}


@router.post("/gets")
async def get_users(
        login: str = Query(...),
        page: int = Query(..., ge=1),
        size: int = Query(..., ge=1, le=100),
        db: DBManager = Depends(get_db)
):
    """
    Get the user list

    POST /gets?login={your_token}&page={page}&size={size}
    Args:
        login: Token.id
        page: page
        size: size
        db: DBManager
    """
    # verify
    validate_jwt(login)
    # get user list
    result = db.get(User, page_info={'page': page, 'size': size})
    if not result.status or not result.data:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"UnExcepted Error: {result.message}")
    # return
    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "data": result.data, "message": "Get users successful"}
    )


@router.put("/update")
async def update_user(
        updateData: UserUpdateData,
        uid: int = Query(...),
        login: str = Query(...),
        db: DBManager = Depends(get_db)
):
    """
    Update user profile

    PUT /update?login={login}
    Args:
        updateData: UserUpdateData
        uid: user.id
        login: Token.id
        db: DBManager
    """
    validate_jwt(login, db)
    user_id = db.get(Token, filters={"token": login}).data[0].user_id
    if user_id != uid and not verify_admin(user_id):  # also admin or user myself only can update user profile
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
                            detail=f"You have not authorized to update user profile")

    user_exist = db.get(User, filters={"id": uid})
    if not user_exist.status or not user_exist.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"User ID {uid} not found")

    origin = user_exist.data[0]
    logger.info(f"{origin} | {type(origin)}")
    updates = {
        "username": updateData.username,
        "password": updateData.password,
        "description": updateData.description,
        "is_admin": updateData.is_admin
    }

    logger.critical(f"U: {updates}")

    for filed, value in updates.items():
        if value is not None:
            setattr(origin, filed, value)

    logger.critical(f"O: {origin}")

    response = db.upsert(origin)

    logger.critical(f"R: {response}")

    if not response.status:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"UnExcepted Error: {response.message}")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "message": "Update user successful"}
    )


@router.delete("/delete")
async def delete_user(
        login: str = Query(...),
        user_id: int = Query(..., ge=1),
        db: DBManager = Depends(get_db)
):
    """
    删除用户（仅管理员可操作，且不能删除自己）
    method: delete
    Args:
        login: Token.id
        user_id: User.id
        db: DBManager
    """
    # 校验token和管理员权限
    validate_jwt(login)
    uid = db.get(Token, filters={"token": login}).data[0]["user_id"]
    if not verify_admin(uid):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Also admin can delete account")
    if uid == user_id:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete your own account")

    user_exist = db.get(User, filters={"id": user_id})
    if not user_exist.status or not user_exist.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"User ID {user_id} not found")

    result = db.delete(User, filters={"id": user_id})
    if not result.status:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"UnExcepted Error: {result.message}")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={
            "status": True,
            "message": "Delete user successful"
        }
    )
